package pl.ps.wi.monitoring.station.services;

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.io.File;
import java.io.IOException;

import pl.ps.wi.monitoring.station.LocalConfiuration;
import pl.ps.wi.monitoring.station.Phone;

import org.jibble.simpleftp.SimpleFTP;

import name.audet.samuel.javacv.*;
import static name.audet.samuel.javacv.jna.cxcore.v20.*;
import static name.audet.samuel.javacv.jna.cv.v20.*;
import static name.audet.samuel.javacv.jna.highgui.v20.*;
import static name.audet.samuel.javacv.jna.cvaux.v20.*;

/**
 * @file Recorder.java
 * @class Recorder
 * @date 04.06.2010
 * @version 1.1
 *
 * @brief Klasa odpowiedzialna za zapis obrazu z zabezpieczonego pomieszczenia i wysłanie filmu na serwer FTP
 *
 */
public class Recorder implements Runnable {

/**
 * Szerokość klatki nagrania
 */
	public static final int FRAME_WIDTH = 320;
/**
 * Wysokość klatki nagrania
 */
	public static final int FRAME_HEIGHT = (int)(0.75 * FRAME_WIDTH);
/**
 * Lokalny katalog do którego trafiają pliki monitoringu
 */
	public static final String LOCAL_DIR = "/root/Desktop/";
/**
 * Port FTP
 */
	public static final int FTP_PORT = 21;
/**
 * Zmienna przechowująca konfigurację aplikacji, przekazaną w konstruktorze
 */
	private LocalConfiuration conf;
/**
 * Wątek prowadzący nagrywanie
 */
	private Thread thread;
/**
 * Numer kamery
 */
	private int device;
/**
 * Czas nagrywania, pobierany z pliku konfiguracyjnego aplikacji
 */
	private int time;
/**
 * Ścieżka do katalogu na serwerze FTP, do którego trafiają nagrania
 */
	private String path;
/**
 * Zmienna logiczna określająca czy wątek działa, zmiany wartości można dokonać poprzez metody start(), stop()
 */
	private volatile boolean run = false;

/**
 * Zmienna służąca do synchronizacji (uniemożliwia kilkukrotne uruchomienie metody i w rezultacie blokadę kamery)
 */
	private static Object lock = new Object();

/**
 * Konstruktor klasy.
 * @param conf Obiekt konfiguracyjny, zawierający opcje nagrywania.
 */
	public Recorder(LocalConfiuration conf) {
		this.conf = conf;
		this.path = conf.getRecDirectory();
		this.device = conf.getRecDevice();
		this.time = conf.getRecTime();
		this.thread = new Thread(this);
	}
/**
 * Metoda uruchamia w odrębnym wątku procedurę nagrywania obrazu z kamery i wysyła go na serwer FTP.
 * Po określonym w pliku konfiguracyjnym czasie wątek samoczynnie kończy się.
 */
	@Override
	public void run() {
		synchronized(lock) {
			Timer t = new Timer();
			t.schedule(new TimerTask() {
						public void run() {
							Recorder.this.stop();
						}
					}, new Date(new Date().getTime() + time));

			String filename = "";

			new JavaCvErrorCallback().redirectError();

			try {
				SimpleDateFormat filetime = new SimpleDateFormat("yyyyMMddHHmmss");
				SimpleDateFormat frametime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

				CvFont font = new CvFont(CV_FONT_HERSHEY_SIMPLEX, 0.6, 0.6, 0.0, 1, 8);

				filename = "cam-" + device + "-" + filetime.format(new Date()) + ".avi";

				String filepath = LOCAL_DIR + filename;

				FrameRecorder recorder = new OpenCVFrameRecorder(filepath, FRAME_WIDTH, FRAME_HEIGHT);
				recorder.setCodecID(CV_FOURCC('D', 'I', 'V', 'X'));
				recorder.start();

				FrameGrabber grabber = new OpenCVFrameGrabber(device);
				grabber.start();
				IplImage image = null;

				while(run && (image = grabber.grab()) != null) {
					String frameinfo = "Cam " + device + ", " + frametime.format(new Date());

					IplImage frame = cvCreateImage(cvSize(FRAME_WIDTH, FRAME_HEIGHT), image.depth, image.nChannels);
					cvResize(image, frame, CV_INTER_AREA);

					cvPutText(frame, frameinfo, cvPoint(0, frame.height-20), font, cvScalar(0, 100, 255, 0));

					recorder.record(frame);
				}

				recorder.stop();
				recorder.release();
				grabber.stop();
				grabber.release();
			} catch(Exception e) {
				System.out.println("Sending message: system under attack");
				Phone.sendAnnihilationMessage();
				//e.printStackTrace();
			}

			SimpleFTP ftp = new SimpleFTP();
			try {
				ftp.connect(conf.getFtpHost(), FTP_PORT, conf.getFtpUser(), conf.getFtpPass());
				ftp.bin();
				ftp.cwd(path);
			} catch (IOException e) {
				e.printStackTrace();
			}

			File root = new File(LOCAL_DIR);

			File tosend = new File(root.getAbsoluteFile() + "/" + filename);

			//System.out.println("Sending: " + tosend.getAbsolutePath());

			try {
				ftp.stor(tosend);
				tosend.delete();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

/**
 * Metoda uruchamia procedurę przechwytywania obrazów z kamery
 */
	public boolean start() {
		if(!run) {
			run = true;
			thread.start();
			return true;
		}
		return false;
	}
/**
 * Metoda zatrzymuje nagrywanie (przed czasem)
 */
	public boolean stop() {
		if(run) {
			run = false;
			try {
				thread.join();
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
			return true;
		}
		return false;
	}
/**
 * Metoda dokonuje sprawdzenia, czy obraz jest nagrywany/wysyłany
 */
	public boolean isRunning() {
		return run;
	}

}
